---
title: IsUserInGroup
summary: Reports direct (non-transitive) membership of a resolved user in a resolved group.
status: draft
owner: "Not determined from source"
last_reviewed: 2026-09-22
---

# IsUserInGroup (OP-18)

## Request and response

| Part | Type | Description |
| --- | --- | --- |
| `inUserId` | `String` | The `SamAccountName` to look up. |
| `inGroupName` | `String` | The group's `SamAccountName` to look up. |
| `inExternalDomain` | `Boolean` | Selects `external.saif.com` when `True`, `corp.saif.com` when `False` ([BR-07](../business-rules.md#br-07-the-directory-domain-is-selected-by-the-caller)) for both the user and the group lookup. |

| Part | Type | Description |
| --- | --- | --- |
| `<return>` | `ADServiceResponse` | `Response` (`EResponse` code) and `Message` (the literal `"True"` or `"False"` on success). |

## WebMethod attributes

`<WebMethod()>` — bare, no arguments supplied.

## Steps

1. No access check is performed ([BR-06](../business-rules.md#br-06-read-only-directory-queries-are-not-access-controlled)).
2. Initialize `myStruc.Response = Success`, `myStruc.Message = String.Empty`.
3. In a `Try` block, call H2 `GetUserPrincipal` with the caller-supplied `inExternalDomain`.
   - If the principal is `Nothing`, set `Response = UserDoesNotExist`.
4. Otherwise, call H3 `GetGroupPrincipal` with `inGroupName` and `inExternalDomain`.
   - If the group principal is `Nothing`, set `Response = GroupDoesNotExist`.
5. Otherwise, set `Message = "True"` when `groupPrin.Members.Contains(userPrin)`, else `Message = "False"` ([BR-32](../business-rules.md#br-32-group-membership-for-isuseringroup-is-direct-only)). This checks **direct** membership only.
   - This differs from `DoesUserHaveResource` (OP-08), which walks **transitive** authorization groups via `GetAuthorizationGroups`: a user entitled only through a nested group answers `"False"` here even though `DoesUserHaveResource` would answer `"True"` for the same user and group — an inconsistent membership semantic across the two operations (SEC-17, HIGH — see [Authentication and authorization](../authentication-authorization.md) and [Tech debt](../tech-debt.md)).
6. `Catch`: set `Response = Failure`, `Message = ex.Message`.
7. `Finally`: release `groupPrin` and `userPrin`.
8. Return the `ADServiceResponse` sentinel.

## Process flow

```mermaid
flowchart TD
    A["Call IsUserInGroup"] --> B["GetUserPrincipal<br>caller-selected domain"]
    B -->|"Nothing"| C["Response = UserDoesNotExist"]
    B -->|"Found"| D["GetGroupPrincipal<br>caller-selected domain"]
    D -->|"Nothing"| E["Response = GroupDoesNotExist"]
    D -->|"Found"| F{"groupPrin.Members<br>.Contains(userPrin)?<br>direct only"}
    F -->|"Yes"| G["Message = True"]
    F -->|"No"| H["Message = False"]
    B -->|"Exception"| I["Response = Failure<br>Message = ex.Message"]
    C --> J["Return ADServiceResponse"]
    E --> J
    G --> J
    H --> J
    I --> J
```

## Shared state effects

None — this operation touches no process-wide state; all locals are per-request.

## Error handling

This operation never faults: an unresolved user, an unresolved group, or any other directory exception is caught and mapped to `Response = Failure` with `ex.Message` in `Message`. See [Faults](../faults.md) for the service-wide fault model.

## Authorization

None in code. This is one of the eleven ungated operations that disclose directory data to any caller who can reach the endpoint. Its direct-only membership semantic also disagrees with `DoesUserHaveResource`'s transitive semantic for the same underlying question (SEC-17, see [Authentication and authorization](../authentication-authorization.md) and [Tech debt](../tech-debt.md)).

## Related documentation
- [Service index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Activation and hosting](../activation-hosting.md)
- [Operations](../operations.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Configuration](../configuration.md)
- [Dependencies](../dependencies.md)
- [Faults](../faults.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

## Sources
- `src\ADUserServices\clsADUserServices.asmx.vb` (lines 715-750)
